using System;
using System.Text.RegularExpressions;
using SmartPeople.Framework.SecuritySpace;

namespace SmartPeople.Framework.SecuritySpace
{
    public sealed class SecurityUsers : ISecurityUsers
    {
        private ISecurityUsersProvider provider;
        //private int noofTriesCount = 0;

        public SecurityUsers(ISecurityUsersProvider provider)
        {
            this.provider = provider;
        }

        private ISecurityUsersProvider Provider
        {
            get { return provider; }
            //set { provider = value; }
        }

        public int Count
        {
            get { return Provider.Count; }
        }

        #region CreateUser(string userName)

        /// <summary>
        /// Creates the user (Blank Password).
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="email">The email.</param>
        /// <returns></returns>
        public ISecurityUser CreateUser(string userName, string email)
        {
            Validate(userName, email);
            return Provider.CreateUser(userName, "", email);
        }

        #endregion

        #region Authenticate(string userName, string password)

        public IToken Authenticate(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentNullException("Username is empty or null!");
            if (String.IsNullOrEmpty(password)) throw new ArgumentNullException("Password is empty or null!");
            return Provider.Authenticate(userName, password);
        }

        #endregion

        #region Authenticate

        public IToken Authenticate(string userName, string password, string ipAddress, DateTime creationDate,
                                   int timeOut, DateTime lastActive)
        {
            return Provider.Authenticate(userName, password, ipAddress, creationDate, timeOut, lastActive);
        }

        #endregion

        #region CreateUser(string userName, string password, string email)

        public ISecurityUser CreateUser(string userName, string password, string email)
        {
            Validate(userName, email);
            return Provider.CreateUser(userName, password, email);
        }

        public ISecurityUser CreateUser(string userName, string password, string email, string passwordQuestion,
                                        string passwordAnswer)
        {
            Validate(userName, email);
            return Provider.CreateUser(userName, password, email, passwordQuestion, passwordAnswer);
        }

        #endregion

        #region CreateUser(string userName, string password, string email, string passwordQuestion,string passwordAnswer, bool isApproved, string comment)

        public ISecurityUser CreateUser(string userName, string password, string email, string passwordQuestion,
                                        string passwordAnswer, bool isApproved, string comment)
        {
            Validate(userName, email, passwordQuestion);
            return Provider.CreateUser(userName, password, email, passwordQuestion, passwordAnswer, isApproved, comment);
        }

        public ISecurityUser CreateUser(string userName, string password, string email, string passwordQuestion,
                                        string passwordAnswer, bool isApproved, string comment, string description,
                                        bool isLockedOut)
        {
            Validate(userName, email, passwordQuestion);
            throw new NotImplementedException();
        }

        #endregion

        #region CreateUser(Guid userGuid)

        public ISecurityUser CreateUser(Guid userGuid)
        {
            return Provider.CreateUser(userGuid);
        }

        #endregion

        #region Validate(string userName)

        public void Validate(string userName)
        {
            ValidateUserName(userName);
        }

        #endregion

        #region Validate(string userName, string email)

        private void Validate(string userName, string email)
        {
            ValidateUserName(userName);
            ValidateEmail(email);
        }

        public void Validate(string userName, string email, string secretQuestion)
        {
            ValidateUserName(userName);
            ValidateEmail(email);
            ValidateSecretQuestion(secretQuestion);
        }

        private void ValidateSecretQuestion(string secretQuestion)
        {
            if (String.IsNullOrEmpty(secretQuestion))
            {
                throw new ArgumentNullException("Secret question cannot be null or empty!");
            }
        }

        #endregion

        #region ValidateEmail(string email)

        private void ValidateEmail(string email)
        {
            //assume email not entered.
            if (String.IsNullOrEmpty(email))
            {
                return;
            }
            string pattern =
                @"^[a-z][a-z|0-9|]*([_][a-z|0-9]+)*([.][a-z|0-9]+([_][a-z|0-9]+)*)?@[a-z][a-z|0-9|]*\.([a-z][a-z|0-9]*(\.[a-z][a-z|0-9]*)?)$";
            Match match = Regex.Match(email.Trim(), pattern, RegexOptions.IgnoreCase);
            if (!match.Success)
            {
                //GetType().FullName
                throw new ArgumentException(email + "is not a valid email id!");
            }
        }

        #endregion

        #region ValidateUserName(string userName)

        public void ValidateUserName(string userName)
        {
            if (String.IsNullOrEmpty(userName))
            {
                throw new ArgumentNullException("Username cannot be null or empty!");
            }

            if (userName.Length <= 1)
            {
                throw new ArgumentException("User Name must be greater than five characters", GetType().FullName);
            }
        }

        #endregion

        #region ValidatePassword(string password)

        //TODO: Check if validation of password must be called?
        public void ValidatePassword(string password)
        {
            if (String.IsNullOrEmpty(password))
            {
                throw new ArgumentNullException("Password cannot be null or empty!");
            }

            if (password.Length <= 4)
            {
                throw new ArgumentException("Password must be greater than four characters!");
            }


            if (!Regex.IsMatch(password, "^[a-zA-Z0-9]*$"))
            {
                throw new ArgumentException("Password must be alphanumeric!");
            }
        }

        #endregion

        #region GetUser(IToken token, bool userIsOnline)

        public ISecurityUser GetUser(IToken token, bool userIsOnline)
        {
            return Provider.GetUser(token, userIsOnline);
        }

        #endregion

        #region GetUser(string userName)

        public ISecurityUser GetUser(string userName)
        {
            return GetUser(userName, false);
        }

        #endregion

        #region GetUser(string userName, bool userIsOnline)

        public ISecurityUser GetUser(string userName, bool userIsOnline)
        {
            return Provider.GetUser(userName, userIsOnline);
        }

        #endregion

        #region GetUsers(string[] userNames)

        public ISecurityUser[] GetUsers(string[] userNames)
        {
            return Provider.GetUsers(userNames);
        }

        #endregion

        #region GetAllUsers()

        public ISecurityUser[] GetAllUsers()
        {
            return provider.GetAllUsers();
        }

        #endregion

        #region GetUserNameByEmail(string email)

        public string GetUserNameByEmail(string email)
        {
            return provider.GetUserNameByEmail(email);
        }

        #endregion

        #region UpdateUser(ISecurityUser user)

        public void UpdateUser(ISecurityUser user)
        {
            Validate(user.UserName, user.Email, user.PasswordQuestion);
            Provider.UpdateUser(user);
        }

        #endregion

        #region UserExists(string userName)

        public bool UserExists(string userName)
        {
            return provider.UserExists(userName);
        }

        #endregion

        #region DeleteUser(string userName)

        public bool DeleteUser(string userName)
        {
            ISecurityUser currentUser = GetUser(userName);
            if (currentUser != null)
            {
                if (currentUser.IsReadOnly)
                {
                    throw new ArgumentException("Cannot delete system created user:" + userName + "!");
                }
            }


            return Provider.DeleteUser(userName, false);
        }

        #endregion

        #region DeleteUser(string userName, bool deleteAllRelatedData)

        public bool DeleteUser(string userName, bool deleteAllRelatedData)
        {
            ISecurityUser currentUser = GetUser(userName);
            if (currentUser != null)
            {
                if (currentUser.IsReadOnly)
                {
                    throw new ArgumentException("Cannot delete system created user:" + userName + "!");
                }
            }

            return Provider.DeleteUser(userName, deleteAllRelatedData);
        }

        #endregion

        #region Clear

        public void Clear()
        {
            Provider.Clear();
        }

        #endregion

        public void SignOut(IToken userToken)
        {
            ISecurityUser currentUser = GetUser(userToken, true);
            currentUser.IsOnline = false;
            currentUser.SessionID = Guid.NewGuid();
            Provider.UpdateUser(currentUser);
            
            
        }
    }
}